#include "fsxwsmainwindow.h"
#include "ui_fsxwsmainwindow.h"
using namespace FsxWsGUI;

//
// Start the web server
//
bool FsxWsMainWindow::startWebServer() {
    bool started = false;
    if (!FsxWsMainWindow::_webServerDispatcher) {
        try {
            FsxWsMainWindow::_webServerDispatcher = new RequestDispatcher(
                        FsxWsMainWindow::_fsxWsSettings->toKmlSettings(),
                        FsxWsMainWindow::_fsxWsSettings->getFmcDataDirectory(), this);
            FsxWsMainWindow::simConnectWebServerSignalSlot();
            started = true;
        } catch (std::exception& ex) {
            QString msg = QString("Exception: ").append(ex.what());
            FsxWsMainWindow::slotLogMessage(msg, QtDebugMsg);
            FsxWsMainWindow::stopWebServer();
        }
    }
    return started;
}

//
// Stop the web server
//
bool FsxWsMainWindow::stopWebServer() {
    bool stopped = false;
    if (FsxWsMainWindow::_webServerDispatcher) {
        FsxWsMainWindow::_webServerDispatcher->terminate();
        stopped = true;
    }
    delete FsxWsMainWindow::_webServerDispatcher;
    FsxWsMainWindow::_webServerDispatcher = nullptr;
    return stopped;
}

//
// Connect WebService to FsxSimConnect
//
void FsxWsMainWindow::simConnectWebServerSignalSlot() {

    // without blocking connection I will not recevive the return value
    if(FsxWsMainWindow::_webServerDispatcher && FsxWsMainWindow::_fsxSimConnect && FsxWsMainWindow::_webServerDispatcher->getWscAircraftsJson()) {
        // From WebServer to FSX SimConnect
        // WebServer queries the global simmconnect
        bool success;
        success = QObject::connect(FsxWsMainWindow::_webServerDispatcher->getWscAircraftsJson(), SIGNAL(signalAircraftsJsonArray(const JsonParameter&)),
                                   FsxWsMainWindow::_fsxSimConnect, SLOT(slotAircraftsJsonArray(const JsonParameter&)), Qt::BlockingQueuedConnection);
        success = QObject::connect(FsxWsMainWindow::_webServerDispatcher->getWscAircraftsHtmlOverview(), SIGNAL(signalAircraftsHtmlTable()),
                                   FsxWsMainWindow::_fsxSimConnect, SLOT(slotAircraftsHtmlTable()), Qt::BlockingQueuedConnection);
        success = QObject::connect(FsxWsMainWindow::_webServerDispatcher->getWscAircraftKmlWaypoints(), SIGNAL(signalAircraftKmlWaypoints(const KmlParameter&)),
                                   FsxWsMainWindow::_fsxSimConnect, SLOT(slotAircraftKmlWaypoints(const KmlParameter&)), Qt::BlockingQueuedConnection);

        if (!success) {
            FsxWsMainWindow::slotLogMessage("No connection of WebService and Window Signal/Slots", QtWarningMsg);
            FsxWsMainWindow::slotSetConsoleTab();
        }
    }
}

//
// Connect to FSX
//
void FsxWsMainWindow::onConnectFSXClicked()
{
    bool connected = FsxWsMainWindow::connectFsxSimConnect();
    QString m = connected ? "Connected to FSX" : "Not connected to FSX, connect failed";
    QtMsgType type = connected ? QtDebugMsg : QtWarningMsg;
    FsxWsMainWindow::slotLogMessage(m, type);
    FsxWsMainWindow::initFsxSimConnectButtons();
    if (!connected) FsxWsMainWindow::slotSetConsoleTab();
}

//
// Disconnect to FSX
//
void FsxWsMainWindow::onDisconnectFSXClicked()
{
    bool disconnected = FsxWsMainWindow::disconnectFsxSimConnect();
    QString m = disconnected ? "Disconnected from FSX" : "Disconnect failed";
    FsxWsMainWindow::slotLogMessage(m, QtDebugMsg);
    FsxWsMainWindow::initFsxSimConnectButtons();
}

//
// Stop the internal web server
//
void FsxWsMainWindow::onStopWebServiceClicked()
{
    bool stopped = FsxWsMainWindow::stopWebServer();
    QString m = stopped ? "WebServer stopped" : "WebServer not stopped";
    FsxWsMainWindow::slotLogMessage(m, QtDebugMsg);
    FsxWsMainWindow::initWebServiceButtons();
}

//
// Start the internal web server
//
void FsxWsMainWindow::onStartWebServiceClicked()
{
    bool started = FsxWsMainWindow::startWebServer() && FsxWsMainWindow::_webServerDispatcher;
    QString m = started ? "WebServer started, " + FsxWsMainWindow::_webServerDispatcher->getSettingsFile() :
                          "WebServer not started";
    FsxWsMainWindow::slotLogMessage(m, QtDebugMsg);
    FsxWsMainWindow::initWebServiceButtons();
}

//
// Aircraft list, selection changed
//
void FsxWsMainWindow::onAircraftListSelectionChanged(const QItemSelection &selected, const QItemSelection&)
{
    QModelIndex mi;
    foreach (mi, selected.indexes()) {
        int row = mi.row();
        QStandardItem* item = FsxWsMainWindow::_aircraftsViewDataModel->item(row, 3);
        QVariant d = item->data(Qt::DisplayRole);
        if (d.isValid()) {
            SIMCONNECT_OBJECT_ID id = d.toInt();
            if (id >=0) {
                FsxWsMainWindow::_lastSelectedAircraft = FsxWsMainWindow::signalFSXFindById(id);
                if (FsxWsMainWindow::_lastSelectedAircraft.isValid() && FsxWsMainWindow::_lastSelectedAircraft.waypointsCount() > 0) {
                    // we do have waypoints (disable in FsxWsMainWindow::initFsxSimConnectButtons)
                    ui->qaMenuFSXSaveWaypoinsKml->setEnabled(true); // allow KML saving
                    ui->qaMenuFSXSaveWaypoinsKmlReducedResolution->setEnabled(true);

                    // new waypoints
                    FsxWsMainWindow::updateWaypointLists(FsxWsMainWindow::_lastSelectedAircraft.getWaypoints(), FsxWsMainWindow::_lastSelectedAircraft.getDeltaWaypoints(), FsxWsMainWindow::_lastSelectedAircraft.getTitle());
                    // select waypoint tabs according to settings
                    if (FsxWsMainWindow::_fsxWsSettings->guiShowWaypointsWhenAircraftSelected())
                        FsxWsMainWindow::slotSetWaypointsTab();
                    break;
                }
            }
        } else {
            FsxWsMainWindow::_lastSelectedAircraft = Aircraft(); // invalid aricraft
            ui->qaMenuFSXSaveWaypoinsKml->setEnabled(false); // disable KML
        }
    }
}

//
// Select the waypoints tab
//
void FsxWsMainWindow::slotSetWaypointsTab() {
    ui->qtwMainTabPanel->setCurrentIndex(MAINTABWAYPOINTS);
}

//
// Select the console tab.
//
void FsxWsMainWindow::slotSetConsoleTab()
{
    ui->qtwMainTabPanel->setCurrentIndex(MAINTABCONSOLE);
}

//
// Show a particular configuration tab
//
void FsxWsMainWindow::showConfigureTab(int index) {
    if (!FsxWsMainWindow::_configureDialog || !FsxWsMainWindow::_fsxWsSettings) return;
    FsxWsMainWindow::_configureDialog->setSettings(FsxWsMainWindow::_fsxWsSettings);
    FsxWsMainWindow::_configureDialog->setTab(index);
    FsxWsMainWindow::_configureDialog->show();
    // ini settings are file written within dialog
}

//
// Connect FSX SimConnect
//
bool FsxWsMainWindow::connectFsxSimConnect() {

    // entry check
    if (FsxWsMainWindow::_fsxSimConnect && FsxWsMainWindow::_fsxSimConnect->isRunning())
        return true; // already running

    bool connected = false;
    FsxWsMainWindow::_fsxSimConnect = new FSXSimConnect(FsxWsMainWindow::_fsxWsSettings->toFsxSimConnectSettings(), this);
    if (FsxWsMainWindow::_fsxSimConnect->openSimConnect()) {
        FsxWsMainWindow::_fsxSimConnect->start();
        FsxWsMainWindow::initGUI2FSXSignalsAndMetadata();
        FsxWsMainWindow::simConnectWebServerSignalSlot();
        connected = true;
    } else {
        FsxWsMainWindow::disconnectFsxSimConnect(); // clean up
        connected = false;
    }
    return connected;
}

//
// Stop FSX SimConnect
//
bool FsxWsMainWindow::disconnectFsxSimConnect(bool hard) {
    bool disconnect = false;
    if (FsxWsMainWindow::_aircraftUpdateTimer) FsxWsMainWindow::_aircraftUpdateTimer->stop();
    if (FsxWsMainWindow::_fsxSimConnect) {
        FsxWsMainWindow::_fsxSimConnect->disconnect(this);
        FsxWsMainWindow::disconnect(FsxWsMainWindow::_fsxSimConnect);
        if (!hard) {
            FsxWsMainWindow::_fsxSimConnect->closeSimConnect();
        }
        disconnect = true;
    }
    // In case of "hard" disconnecting (e.g. FSX shuts down) the dispatcher might
    // return asynchronously later => crash! So I keep the object dangling (memory leak),
    // Qt will later remove it
    if (!hard) delete FsxWsMainWindow::_fsxSimConnect;
    FsxWsMainWindow::_fsxSimConnect = nullptr;
    return disconnect;
}

//
// Update the aircrafts list (table view)
//
void FsxWsMainWindow::updateAircraftList(const QList<Aircraft> &aircrafts)
{
    FsxWsMainWindow::_aircraftsViewDataModel->removeRows(0, FsxWsMainWindow::_aircraftsViewDataModel->rowCount());
    FsxWsMainWindow::addAircraftsToView(aircrafts);
}

//
// Update the waypoints list (table view)
//
void FsxWsMainWindow::updateWaypointLists(const QList<Waypoint> &waypoints, const QList<Waypoint> &deltaWaypoints, const QString title)
{
    QString t = title.length() > 0 ? "Waypoints: '" + title + "'" : "Waypoints";
    ui->qtvWaypointList->setToolTip(t);
    ui->qtwMainTabPanel->setTabText(1,t);
    FsxWsMainWindow::_waypointsViewDataModel->removeRows(0, FsxWsMainWindow::_waypointsViewDataModel->rowCount());
    FsxWsMainWindow::_deltaWaypointsViewDataModel->removeRows(0, FsxWsMainWindow::_deltaWaypointsViewDataModel->rowCount());
    FsxWsMainWindow::addWaypointsToView(FsxWsMainWindow::_waypointsViewDataModel, waypoints);
    FsxWsMainWindow::addWaypointsToView(FsxWsMainWindow::_deltaWaypointsViewDataModel, deltaWaypoints);
}

//
// Write a log message
//
void FsxWsMainWindow::slotLogMessage(const QString &logMessage, QtMsgType msgType)
{
    if (logMessage.isEmpty()) return;
    ui->qtbConsole->append(logMessage);
    FsxWsMainWindow::loggerMessage(logMessage, msgType);
}

//
// If logger exists, write a logger message, otherwise use qDebug
//
void FsxWsMainWindow::loggerMessage(const QString &msg, QtMsgType type) const {
    if (FsxWsMainWindow::_logger)
        FsxWsMainWindow::_logger->log(type, msg);
    else
        qDebug() << msg;
}

//
// Message loop of FSX has been stopped, e.g. FSX shut down
//
void FsxWsMainWindow::slotFSXMessageLoopStopped() {
    FsxWsMainWindow::slotFSXQuit();
}

//
// FSX shutting down
//
void FsxWsMainWindow::slotFSXQuit() {
    FsxWsMainWindow::slotLogMessage("FSX is going down", QtDebugMsg);
    FsxWsMainWindow::disconnectFsxSimConnect(true);
    FsxWsMainWindow::initFsxSimConnectButtons();
}

//
// Update the aircrafts
//
void FsxWsMainWindow::slotUpdateAircrafts() {
    // entry checks
    if (!FsxWsMainWindow::_fsxSimConnect) return;
    if (!FsxWsMainWindow::_fsxSimConnect->isRunning()) return;

    // only update if window is visible (save CPU)
    if (FsxWsMainWindow::isMinimized() || FsxWsMainWindow::isHidden()) return;

    // Direct call: QList<Aircraft> aircrafts = FsxWsMainWindow::_fsxSimConnect->slotAircrafts();
    QList<Aircraft> aircrafts = FsxWsMainWindow::signalFSXAircrafts();
    FsxWsMainWindow::updateAircraftList(aircrafts);
}
